// Copyright Epic Games, Inc. All Rights Reserved.

#include "Teams/AsyncAction_ObserveTeamColors.h"

#include "Engine/Engine.h"
#include "Engine/World.h"
#include "Teams/LyraTeamAgentInterface.h"
#include "Teams/LyraTeamStatics.h"
#include "Teams/LyraTeamSubsystem.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(AsyncAction_ObserveTeamColors)

/**
 * 构造函数
 */
UAsyncAction_ObserveTeamColors::UAsyncAction_ObserveTeamColors(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

/**
 * 观察团队颜色的静态方法
 */
UAsyncAction_ObserveTeamColors* UAsyncAction_ObserveTeamColors::ObserveTeamColors(UObject* TeamAgent)
{
	UAsyncAction_ObserveTeamColors* Action = nullptr; // 初始化动作为空

	if (TeamAgent != nullptr) // 如果团队代理有效
	{
		Action = NewObject<UAsyncAction_ObserveTeamColors>(); // 创建新的观察团队颜色动作对象
		Action->TeamInterfacePtr = TWeakInterfacePtr<ILyraTeamAgentInterface>(TeamAgent); // 设置团队接口弱指针
		Action->TeamInterfaceObj = TeamAgent; // 设置团队接口对象
		Action->RegisterWithGameInstance(TeamAgent); // 注册到游戏实例
	}

	return Action; // 返回创建的动作
}

/**
 * 设置准备销毁
 */
void UAsyncAction_ObserveTeamColors::SetReadyToDestroy()
{
	Super::SetReadyToDestroy(); // 调用父类方法

	// 如果正在取消，需要取消所有可能正在监听的钩子
	if (ILyraTeamAgentInterface* TeamInterface = TeamInterfacePtr.Get()) // 如果团队接口有效
	{
		TeamInterface->GetTeamChangedDelegateChecked().RemoveAll(this); // 移除所有监听
	}
}

/**
 * 激活异步操作
 */
void UAsyncAction_ObserveTeamColors::Activate()
{
	bool bCouldSucceed = false; // 初始化成功标志为false
	int32 CurrentTeamIndex = INDEX_NONE; // 当前团队索引初始化为无
	ULyraTeamDisplayAsset* CurrentDisplayAsset = nullptr; // 当前显示资源初始化为空

	if (ILyraTeamAgentInterface* TeamInterface = TeamInterfacePtr.Get()) // 如果团队接口有效
	{
		if (UWorld* World = GEngine->GetWorldFromContextObject(TeamInterfaceObj.Get(), EGetWorldErrorMode::LogAndReturnNull)) // 获取世界上下文
		{
			// 获取当前团队信息
			CurrentTeamIndex = GenericTeamIdToInteger(TeamInterface->GetGenericTeamId()); // 获取当前团队索引
			CurrentDisplayAsset = ULyraTeamStatics::GetTeamDisplayAsset(World, CurrentTeamIndex); // 获取团队显示资源

			// 监听未来的团队变化
			TeamInterface->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnWatchedAgentChangedTeam); // 添加动态委托监听

			bCouldSucceed = true; // 设置成功标志为true
		}
	}

	// 广播一次以便用户获取当前状态
	BroadcastChange(CurrentTeamIndex, CurrentDisplayAsset); // 广播变化

	// 如果无法绑定到委托，我们将永远不会获得任何额外更新
	if (!bCouldSucceed) // 如果不成功
	{
		SetReadyToDestroy(); // 设置准备销毁
	}
}

/**
 * 广播团队变化
 */
void UAsyncAction_ObserveTeamColors::BroadcastChange(int32 NewTeam, const ULyraTeamDisplayAsset* DisplayAsset)
{
	UWorld* World = GEngine->GetWorldFromContextObject(TeamInterfaceObj.Get(), EGetWorldErrorMode::LogAndReturnNull); // 获取世界
	ULyraTeamSubsystem* TeamSubsystem = UWorld::GetSubsystem<ULyraTeamSubsystem>(World); // 获取团队子系统

	const bool bTeamChanged = (LastBroadcastTeamId != NewTeam); // 检查团队是否变化

	// 停止监听旧团队
	if ((TeamSubsystem != nullptr) && bTeamChanged && (LastBroadcastTeamId != INDEX_NONE)) // 如果团队子系统有效且团队已变化且旧团队有效
	{
		TeamSubsystem->GetTeamDisplayAssetChangedDelegate(LastBroadcastTeamId).RemoveAll(this); // 移除旧团队监听
	}

	// 广播
	LastBroadcastTeamId = NewTeam; // 更新最后广播的团队ID
	OnTeamChanged.Broadcast(NewTeam != INDEX_NONE, NewTeam, DisplayAsset); // 广播团队变化

	// 开始监听新团队
	if ((TeamSubsystem != nullptr) && bTeamChanged && (NewTeam != INDEX_NONE)) // 如果团队子系统有效且团队已变化且新团队有效
	{
		TeamSubsystem->GetTeamDisplayAssetChangedDelegate(NewTeam).AddDynamic(this, &ThisClass::OnDisplayAssetChanged); // 添加新团队监听
	}
}

/**
 * 当监视的代理团队变化时调用
 */
void UAsyncAction_ObserveTeamColors::OnWatchedAgentChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam)
{
	ULyraTeamDisplayAsset* DisplayAsset = ULyraTeamStatics::GetTeamDisplayAsset(TeamAgent, NewTeam); // 获取新团队的显示资源
	BroadcastChange(NewTeam, DisplayAsset); // 广播变化
}

/**
 * 当显示资源变化时调用
 */
void UAsyncAction_ObserveTeamColors::OnDisplayAssetChanged(const ULyraTeamDisplayAsset* DisplayAsset)
{
	BroadcastChange(LastBroadcastTeamId, DisplayAsset); // 广播变化
}